import { GameStatus, MoveDirectionEnum } from "./Enum";
import { Square } from "./Square";
import { SquareGroup } from "./SquareGroup";
import { createTetris } from "./Tetris";
import { TetrisRule } from "./TetrisRule";
import { nextTetrisTipBoxConf } from "./config/nextTetrisTipBoxConf";
import panelConf from "./config/panelConf";
import { GameShowPage } from "./viewer/GameShowPage";

export class Game {
  // 游戏状态
  private _gameStatus: GameStatus = GameStatus.pending;
  // 操作的当前方块
  private _curTetris?: SquareGroup;
  // 下一个方块
  private _nextTetris: SquareGroup = createTetris({ x: 0, y: 0 });
  // 计时器
  private _timer?: any;
  // 间隔时间
  private _duration: number = 1000;
  // 已经触底的方块
  private _esists: Square[] = [];
  // 分数
  private _score: number = 0;

  constructor(private _gameViewer: GameShowPage) {
    this.setCurTetrisCenter(this._nextTetris, nextTetrisTipBoxConf.width);
    this._gameViewer.showNextTetris(this._nextTetris);
    this._gameViewer.init(this);
  }

  /**
   * 开始游戏
   */
  public start() {
    if (this._gameStatus === GameStatus.payling) {
      return;
    }
    this._gameStatus = GameStatus.payling;

    if (!this._curTetris) {
      this.switchTetris();
    }
    this.autoDown();

    this._gameViewer.onStart();
  }

  /**
   * 让当前方块自动下落
   */
  public autoDown() {
    if (this._timer || this._gameStatus !== GameStatus.payling) {
      return;
    }

    this._timer = setInterval(() => {
      if (this._curTetris) {
        if (!TetrisRule.move(this._curTetris, MoveDirectionEnum.down, this._esists)) {
          // 进入此if证明触底
          this.hitBottom();
        }
      }
    }, this._duration);
  }

  /**
   * 切换方块
   */
  public switchTetris() {
    // 将方块显示至游戏面板
    this._curTetris = this._nextTetris;
    this._gameViewer.removeNextTetris(this._nextTetris);
    this.setCurTetrisCenter(this._curTetris, panelConf.width);
    // 判断游戏是否结束
    if (!TetrisRule.isCanMove(this._curTetris.shape, this._curTetris.centerPoint, this._esists)) {
      this.gameOver();
      return;
    }

    this._gameViewer.showCurTetris(this._curTetris);

    // 生成下一个方块
    this._nextTetris = createTetris({ x: 0, y: 0 });
    this.setCurTetrisCenter(this._nextTetris, nextTetrisTipBoxConf.width);
    this._gameViewer.showNextTetris(this._nextTetris);
  }

  /**
   * 将方块设置在容器中间
   */
  public setCurTetrisCenter(tetris: SquareGroup, width: number) {
    const x = Math.floor(width / 2);
    let y = 0;

    tetris.squares.forEach((sq) => {
      if (sq.point.y < y) {
        y = sq.point.y;
      }
    });

    tetris.centerPoint = {
      x: x,
      y: tetris.centerPoint.y + Math.abs(y),
    };
  }

  public toLeft() {
    if (this._curTetris && this._gameStatus === GameStatus.payling) {
      TetrisRule.move(this._curTetris, MoveDirectionEnum.left, this._esists);
    }
  }

  public toRight() {
    if (this._curTetris && this._gameStatus === GameStatus.payling) {
      TetrisRule.move(this._curTetris, MoveDirectionEnum.right, this._esists);
    }
  }

  public toBottom() {
    if (this._curTetris && this._gameStatus === GameStatus.payling) {
      TetrisRule.moveToEnd(this._curTetris, MoveDirectionEnum.down, this._esists);
      this.hitBottom();
    }
  }

  public rotate() {
    if (this._curTetris && this._gameStatus === GameStatus.payling) {
      TetrisRule.rotate(this._curTetris, this._esists);
    }
  }

  private hitBottom() {
    if (!this._curTetris) {
      return;
    }
    this._esists.push(...this._curTetris.squares);
    this.incrementScope(TetrisRule.clearSquare(this._esists));
    this.switchTetris();
  }

  private gameOver(): void {
    this._gameStatus = GameStatus.over;
    clearInterval(this._timer);
    this._gameViewer.onOver();
  }

  private incrementScope(lineCount: number) {
    if (lineCount === 0) {
      return;
    }

    this._score += lineCount * 10;
    this._gameViewer.onScore(this._score);
  }

  public pauseGame() {
    clearInterval(this._timer);
    this._timer = null;
    this._gameStatus = GameStatus.pause;
    this._gameViewer.onPause();
  }

  public get gameStatus() {
    return this._gameStatus;
  }
}
